package com.sky.skyopsserver.controller;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.sky.skyopsserver.aspect.ApiOperationLog;
import com.sky.skyopsserver.service.CredentialService;
import com.sky.skyopsserver.utils.PageResponse;
import com.sky.skyopsserver.utils.Response;
import com.sky.skyopsserver.vos.*;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Positive;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.Map;

/**
 * 凭据信息控制器
 * 
 * @author Administrator
 * @since 2025-01-17
 */
@Slf4j
@RestController
@RequestMapping("/api/credential")
@RequiredArgsConstructor
@Validated
@Tag(name = "凭据管理", description = "凭据信息的增删改查操作")
public class CredentialController {

    private final CredentialService credentialService;

    /**
     * 添加凭据
     * 
     * @param reqVO 添加凭据请求VO
     * @return 凭据ID
     */
    @PostMapping("/add")
    @Operation(summary = "添加凭据", description = "新增一个凭据信息")
    @ApiOperationLog(description = "添加凭据")
    public Response<Long> addCredential(@Valid @RequestBody CredentialAddReqVO reqVO) {
        Long credentialId = credentialService.addCredential(reqVO);
        return Response.success(credentialId);
    }

    /**
     * 更新凭据信息
     * 
     * @param reqVO 更新凭据请求VO
     * @return 操作结果
     */
    @PutMapping("/update")
    @Operation(summary = "更新凭据信息", description = "修改凭据的基本信息")
    @ApiOperationLog(description = "更新凭据信息")
    public Response<Boolean> updateCredential(@Valid @RequestBody CredentialUpdateReqVO reqVO) {
        Boolean result = credentialService.updateCredential(reqVO);
        return Response.success(result);
    }

    /**
     * 删除凭据
     * 
     * @param id 凭据ID
     * @return 操作结果
     */
    @DeleteMapping("/delete/{id}")
    @Operation(summary = "删除凭据", description = "根据ID删除指定凭据")
    @ApiOperationLog(description = "删除凭据")
    public Response<Boolean> deleteCredential(
            @Parameter(description = "凭据ID", required = true)
            @PathVariable("id") @NotNull(message = "凭据ID不能为空") @Positive(message = "凭据ID必须为正数") Long id) {
        Boolean result = credentialService.deleteCredential(id);
        return Response.success(result);
    }

    /**
     * 批量删除凭据
     * 
     * @param ids 凭据ID列表
     * @return 操作结果
     */
    @DeleteMapping("/batch-delete")
    @Operation(summary = "批量删除凭据", description = "根据ID列表批量删除凭据")
    @ApiOperationLog(description = "批量删除凭据")
    public Response<Boolean> batchDeleteCredential(
            @Parameter(description = "凭据ID列表", required = true)
            @RequestBody @NotEmpty(message = "凭据ID列表不能为空") List<@Positive(message = "凭据ID必须为正数") Long> ids) {
        Boolean result = credentialService.batchDeleteCredential(ids);
        return Response.success(result);
    }

    /**
     * 根据ID查询凭据详情
     * 
     * @param id 凭据ID
     * @return 凭据详情
     */
    @GetMapping("/detail/{id}")
    @Operation(summary = "查询凭据详情", description = "根据ID获取凭据的详细信息")
    @ApiOperationLog(description = "查询凭据详情")
    public Response<CredentialRspVO> getCredentialById(
            @Parameter(description = "凭据ID", required = true)
            @PathVariable("id") @NotNull(message = "凭据ID不能为空") @Positive(message = "凭据ID必须为正数") Long id) {
        CredentialRspVO result = credentialService.getCredentialById(id);
        return Response.success(result);
    }

    /**
     * 分页查询凭据列表
     * 
     * @param reqVO 分页查询请求VO
     * @return 分页结果
     */
    @PostMapping("/page")
    @Operation(summary = "分页查询凭据列表", description = "根据条件分页查询凭据信息")
    @ApiOperationLog(description = "分页查询凭据列表")
    public PageResponse<CredentialRspVO> getCredentialPage(@Valid @RequestBody CredentialPageReqVO reqVO) {
        IPage<CredentialRspVO> page = credentialService.getCredentialPage(reqVO);
        return PageResponse.success(page, page.getRecords());
    }

    /**
     * 查询所有凭据选项（用于下拉选择）
     * 
     * @return 凭据选项列表
     */
    @GetMapping("/options")
    @Operation(summary = "查询凭据选项", description = "获取所有凭据的选项列表，用于下拉选择")
    @ApiOperationLog(description = "查询凭据选项")
    public Response<List<CredentialOptionRspVO>> getAllCredentialOptions() {
        List<CredentialOptionRspVO> result = credentialService.getAllCredentialOptions();
        return Response.success(result);
    }

    /**
     * 根据认证方式查询凭据选项
     * 
     * @param type 认证方式
     * @return 凭据选项列表
     */
    @GetMapping("/options/type/{type}")
    @Operation(summary = "根据认证方式查询凭据选项", description = "根据指定认证方式获取凭据选项列表")
    @ApiOperationLog(description = "根据认证方式查询凭据选项")
    public Response<List<CredentialOptionRspVO>> getCredentialOptionsByType(
            @Parameter(description = "认证方式", required = true)
            @PathVariable("type") @NotNull(message = "认证方式不能为空") @Positive(message = "认证方式必须为正数") Integer type) {
        List<CredentialOptionRspVO> result = credentialService.getCredentialOptionsByType(type);
        return Response.success(result);
    }

    /**
     * 查询有主机使用的凭据选项
     * 
     * @return 凭据选项列表
     */
    @GetMapping("/options/with-hosts")
    @Operation(summary = "查询有主机使用的凭据选项", description = "获取被主机使用的凭据选项列表")
    @ApiOperationLog(description = "查询有主机使用的凭据选项")
    public Response<List<CredentialOptionRspVO>> getCredentialOptionsWithHosts() {
        List<CredentialOptionRspVO> result = credentialService.getCredentialOptionsWithHosts();
        return Response.success(result);
    }

    /**
     * 查询未使用的凭据选项
     * 
     * @return 凭据选项列表
     */
    @GetMapping("/options/unused")
    @Operation(summary = "查询未使用的凭据选项", description = "获取未被主机使用的凭据选项列表")
    @ApiOperationLog(description = "查询未使用的凭据选项")
    public Response<List<CredentialOptionRspVO>> getUnusedCredentialOptions() {
        List<CredentialOptionRspVO> result = credentialService.getUnusedCredentialOptions();
        return Response.success(result);
    }

    /**
     * 获取凭据统计信息
     * 
     * @return 凭据统计信息
     */
    @GetMapping("/statistics")
    @Operation(summary = "获取凭据统计信息", description = "获取凭据的各项统计数据")
    @ApiOperationLog(description = "获取凭据统计信息")
    public Response<CredentialStatisticsRspVO> getCredentialStatistics() {
        CredentialStatisticsRspVO result = credentialService.getCredentialStatistics();
        return Response.success(result);
    }

    /**
     * 检查凭据名称是否已存在
     * 
     * @param name 凭据名称
     * @param excludeId 排除的凭据ID（可选）
     * @return 是否存在
     */
    @GetMapping("/check-name")
    @Operation(summary = "检查凭据名称", description = "检查凭据名称是否已存在")
    @ApiOperationLog(description = "检查凭据名称")
    public Response<Boolean> checkCredentialNameExists(
            @Parameter(description = "凭据名称", required = true)
            @RequestParam("name") @NotBlank(message = "凭据名称不能为空") String name,
            @Parameter(description = "排除的凭据ID")
            @RequestParam(value = "excludeId", required = false) Long excludeId) {
        Boolean result = credentialService.checkCredentialNameExists(name, excludeId);
        return Response.success(result);
    }

    /**
     * 根据名称模糊查询凭据
     * 
     * @param name 凭据名称关键字
     * @return 凭据列表
     */
    @GetMapping("/search/name")
    @Operation(summary = "按名称搜索凭据", description = "根据凭据名称关键字模糊查询凭据")
    @ApiOperationLog(description = "按名称搜索凭据")
    public Response<List<CredentialRspVO>> searchCredentialByName(
            @Parameter(description = "凭据名称关键字", required = true)
            @RequestParam("name") @NotBlank(message = "凭据名称关键字不能为空") String name) {
        List<CredentialRspVO> result = credentialService.searchCredentialByName(name);
        return Response.success(result);
    }

    /**
     * 根据用户名模糊查询凭据
     * 
     * @param account 用户名关键字
     * @return 凭据列表
     */
    @GetMapping("/search/account")
    @Operation(summary = "按用户名搜索凭据", description = "根据用户名关键字模糊查询凭据")
    @ApiOperationLog(description = "按用户名搜索凭据")
    public Response<List<CredentialRspVO>> searchCredentialByAccount(
            @Parameter(description = "用户名关键字", required = true)
            @RequestParam("account") @NotBlank(message = "用户名关键字不能为空") String account) {
        List<CredentialRspVO> result = credentialService.searchCredentialByAccount(account);
        return Response.success(result);
    }

    /**
     * 验证凭据类型是否有效
     * 
     * @param type 凭据类型
     * @return 是否有效
     */
    @GetMapping("/validate-type")
    @Operation(summary = "验证凭据类型", description = "验证凭据类型是否有效")
    @ApiOperationLog(description = "验证凭据类型")
    public Response<Boolean> validateCredentialType(
            @Parameter(description = "凭据类型", required = true)
            @RequestParam("type") @NotNull(message = "凭据类型不能为空") Integer type) {
        Boolean result = credentialService.validateCredentialType(type);
        return Response.success(result);
    }

    /**
     * 验证凭据信息完整性
     * 
     * @param type 认证方式
     * @param password 密码
     * @param secretKey 密钥
     * @return 是否有效
     */
    @PostMapping("/validate-info")
    @Operation(summary = "验证凭据信息完整性", description = "验证凭据信息是否完整")
    @ApiOperationLog(description = "验证凭据信息完整性")
    public Response<Boolean> validateCredentialInfo(
            @Parameter(description = "认证方式", required = true)
            @RequestParam("type") @NotNull(message = "认证方式不能为空") Integer type,
            @Parameter(description = "密码")
            @RequestParam(value = "password", required = false) String password,
            @Parameter(description = "密钥")
            @RequestParam(value = "secretKey", required = false) String secretKey) {
        Boolean result = credentialService.validateCredentialInfo(type, password, secretKey);
        return Response.success(result);
    }

    /**
     * 测试凭据连接
     * 
     * @param credentialId 凭据ID
     * @param host 主机地址
     * @param port 端口
     * @return 连接测试结果
     */
    @PostMapping("/test-connection")
    @Operation(summary = "测试凭据连接", description = "测试凭据是否能够成功连接到指定主机")
    @ApiOperationLog(description = "测试凭据连接")
    public Response<Boolean> testCredentialConnection(
            @Parameter(description = "凭据ID", required = true)
            @RequestParam("credentialId") @NotNull(message = "凭据ID不能为空") @Positive(message = "凭据ID必须为正数") Long credentialId,
            @Parameter(description = "主机地址", required = true)
            @RequestParam("host") @NotBlank(message = "主机地址不能为空") String host,
            @Parameter(description = "端口", required = true)
            @RequestParam("port") @NotNull(message = "端口不能为空") @Positive(message = "端口必须为正数") Integer port) {
        Boolean result = credentialService.testCredentialConnection(credentialId, host, port);
        return Response.success(result);
    }

    /**
     * 获取所有认证方式列表
     * 
     * @return 认证方式列表
     */
    @GetMapping("/types")
    @Operation(summary = "获取认证方式列表", description = "获取所有支持的认证方式列表")
    @ApiOperationLog(description = "获取认证方式列表")
    public Response<List<Map<String, Object>>> getAllCredentialTypes() {
        List<Map<String, Object>> result = credentialService.getAllCredentialTypes();
        return Response.success(result);
    }

    /**
     * 获取凭据下的主机数量
     * 
     * @param credentialId 凭据ID
     * @return 主机数量
     */
    @GetMapping("/host-count/{credentialId}")
    @Operation(summary = "获取凭据主机数量", description = "获取指定凭据下的主机数量")
    @ApiOperationLog(description = "获取凭据主机数量")
    public Response<Long> getHostCountByCredentialId(
            @Parameter(description = "凭据ID", required = true)
            @PathVariable("credentialId") @NotNull(message = "凭据ID不能为空") @Positive(message = "凭据ID必须为正数") Long credentialId) {
        Long result = credentialService.getHostCountByCredentialId(credentialId);
        return Response.success(result);
    }
}